import decimal

from django.db import transaction
from django.db.migrations import serializer
from django.shortcuts import render
from rest_framework import viewsets, status, serializers
from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.viewsets import ReadOnlyModelViewSet, ModelViewSet

from jt32.settings import alipy
from shopping.models import Classification, Commodity, CommodityImg, ShoppingCart, Order, OrderGoods, Payment
from shopping.serializers import ClassificationSerializer, ClassificationSerializerSimple, CommoditySerializer, \
    ShoppingCartSerializer, OrderSerializer, PaymentSerializer
from  datetime import datetime
import random
# 导入 fastdfs
from fdfs_client.client import Fdfs_client,get_tracker_conf

from users.models import Address
from celery_tasks.email.tasks import send_mail_task
#根据配置信息得到 连接信息地址 连接fastdfs
client = get_tracker_conf("fastdfs/client.conf")
# 得到客户端对象
client = Fdfs_client(client)
import logging
# 得到日志对象
logger = logging.getLogger(__name__)

# Create your views here.


# 商品分类
# admin 后台进行统一关联
# 对外的查询接口

class ClassificationViewSet(ReadOnlyModelViewSet):
    queryset = Classification.objects.filter(is_delete=False)
    serializer_class = ClassificationSerializer
    permission_classes = [IsAuthenticated]

    # 查看所有分类的时候
    # 应该展示的一级分类
    # 指定id 1  ==》 python基础里面的  子级分类展示出来

    # 查询集
    # 如果是 list方法 就展示 没有父级的  分类数据
    def get_queryset(self):
        # 重写查询集
        if self.action in ["list"]:
            # parent 字段为空的数据 查询出来
            return self.queryset.filter(parent__isnull=True)
        return self.queryset

    # 重写序列器
    def get_serializer_class(self):
        if self.action in ["list"]:
            return ClassificationSerializerSimple
        # return ClassificationSerializer
        return self.serializer_class



    # 展示分类下面的商品数据
    # @action(methods=["get"], detail=True)
    # def commodity(self,request,pk):
    #     # 获取分类的数据
    #     try:
    #         # classificationres模型对象
    #         classificationres = self.get_queryset().get(id = pk)
    #     except Classification.DoesNotExist:
    #         return Response(status=status.HTTP_404_NOT_FOUND)
    #
    #
    #     # 乐观的假设 提前用filter_field 保存要操作的字段名
    #     filter_field = "classification1_set"
    #     classificationres_name = classificationres.name
    #     # 怎么判断是一级分类 还是二级分类呢
    #     if classificationres.parent :
    #         # 二级分类
    #         filter_field = "classification2_set"
    #         classificationres_name = f"{classificationres.parent.name}--{classificationres.name}"
    #
    #     # 商品分类查 商品数据   反向查询
    #     # 用模型名_set  classification1_set  classification2_set
    #     # 分类模型.classification1_set  问题是什么呢？
    #     # 分类模型.classification2_set
    #     # classificationres.'classification1_set' ==> classificationres.classification1_set
    #     # classificationres.'classification2_set' ==> classificationres.classification2_set
    #
    #     # 序列化返回
    #     # getattr(aa, "name")
    #     # 分类模型.反向关联查询得到商品数据
    #     commodityres = getattr(classificationres, filter_field)
    #     # data 商品数据
    #     commodityserializer = CommoditySerializer(commodityres, many=True)
    #     return Response({
    #         "commodity":commodityserializer.data,
    #         "classification":classificationres_name
    #     })


    @action(methods=["get"], detail=True)
    def commodity(self,request,pk):
        # 获取分类的数据
        try:
            # classificationres模型对象
            classificationres = self.get_queryset().get(id = pk)
        except Classification.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)


        # 乐观的假设 提前用filter_field 保存要操作的字段名
        filter_field = "classification1"
        classificationres_name = classificationres.name
        # 怎么判断是一级分类 还是二级分类呢
        if classificationres.parent :
            # 二级分类
            filter_field = "classification2"
            classificationres_name = f"{classificationres.parent.name}--{classificationres.name}"

        # 查询方法

        filte_kwargs ={
            filter_field:classificationres,
            "is_delete":False,
            "status":1
        }
        # Commodity.objects.filter(classification1 = 分类模型)
        # Commodity.objects.filter(classification2 = 分类模型)
        # Commodity.objects.filter(classification2_id = 分类模型id)
        # 不是反向查询  商品 查询 分类的


        commodityres = Commodity.objects.filter(**filte_kwargs)

        commodityserializer = CommoditySerializer(commodityres, many=True)
        return Response({
            "commodity":commodityserializer.data,
            "classification":classificationres_name
        })






# 商品视图
class CommodityViewSet(ModelViewSet):
    queryset = Commodity.objects.filter(is_delete=False)
    serializer_class = CommoditySerializer
    permission_classes = [IsAuthenticated]

    # 重写 create方法
    # 二个模型的数据存储
    def create(self, request, *args, **kwargs):
        # 得到前端传入的商品数据 商品分类的id数据
        # request.data  反序列化  校验
        # 创建
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()

        # 商品图片的存储  getlist 多个图片数据
        files =  request.FILES.getlist('file')

        for file in files: # file 单独的图片
            if file:
                # 判断是不是图片数据
                if file.content_type not in ["image/png", "image/jpeg"]:
                    # 不是图片报错异常
                    return Response({"detail": "仅支持png或者jpg的格式"}, status=status.HTTP_400_BAD_REQUEST)

                # 获取文件后缀  xxx.png  xxx.jpg
                try:
                    image_ext_name = file.name.split('.')[-1]
                except Exception as e:
                    logger.info(f"图片扩展名异常 {e}")
                    image_ext_name = "png"
                # 上传到fastdfs
                try:
                    upload_res = client.upload_by_buffer(file.read(), file_ext_name=image_ext_name)
                except Exception as e:
                    logger.error(f"图片上传异常{e}")
                    return Response({"detail": "图片上传错误"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
                # 判断是否成功
                if upload_res.get("Status") != "Upload successed.":
                    logger.error(f"图片上传失败{e}")
                    return Response({"detail": "图片上传失败"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
                # 得到新头像的地址                       decode() 解码成字符数据
                image_url = upload_res.get("Remote file_id").decode()

                # 图片存储进入的 图模型当中
                CommodityImg.objects.create(src = image_url,commodity_id = serializer.data["id"])


        return Response(serializer.data)



    # 商品优选展示
    @action(methods=["get"],detail=False)
    def optimization(self,request):
        # 展示优选商品  排序操作
        # 得到所有的商品数据  进行排序   考前的展示出来
        queryres = self.get_queryset().order_by("-sales").order_by("-comments")
        if len(queryres)  >= 5:
            queryres = queryres[:5]
        # 序列化返回
        serializer = self.get_serializer(queryres, many=True)
        return Response(serializer.data)







# 购物车视图
class ShoppingCartViewSet(ModelViewSet):
    queryset = ShoppingCart.objects.all()
    serializer_class = ShoppingCartSerializer
    permission_classes = [IsAuthenticated]

    # 查询集  当前用户只能看到自己的购物车
    def get_queryset(self):
        return  self.request.user.shoppingcart_set.all()


    def create(self, request, *args, **kwargs):
        request.POST._mutable = True
        request.data["user"] = request.user.id
        commodity_id = request.data["commodity"]
        number = request.data["number"]
        # 判断一下 改商品之前是否有进行添加过 当前用户  购物车模型数据  7  1    7  5
        existing_item = ShoppingCart.objects.filter(user = request.user,commodity_id = commodity_id).first()

        if existing_item:
            # 修改操作
            serializer = self.get_serializer(instance = existing_item,data = {
                'user': request.user.id,
                "commodity": commodity_id,
                "number": existing_item.number + number
            } )
            serializer.is_valid(raise_exception=True)
            serializer.save()
            return Response(serializer.data)

        else:
            return ModelViewSet.create(self, request, *args, **kwargs)




# 订单视图
class OrderViewSet(ModelViewSet):
    queryset = Order.objects.all()
    serializer_class = OrderSerializer
    permission_classes = [IsAuthenticated]

    # 查询集  当前用户只能看到自己的订单
    def get_queryset(self):
        return  self.request.user.order_set.all()


    # 重写create方法
    # 订单的生成

    # 针对一个功能函数，如果出现了多个修改  那么需要考虑  事务的操作

    def create(self, request, *args, **kwargs):
        #request.data =  {address: 6, pay_method: "1", cart: ["2", "1"]}
        # 地址信息
        # 支付方式
        # 购物车的关联id
        data =request.data
        user = request.user
        carts = data.get("cart")
        pay_method = data.get("pay_method")
        address_id = data.get("address")

        # 校验购物车的数据
        if not carts:
            return Response({"error":"cart数据不存在"},status=status.HTTP_400_BAD_REQUEST)
        # 校验地址数据
        try:
            address = Address.objects.get(id=address_id)
        except Address.DoesNotExist:
            return Response({"error":"地址数据不存在"},status=status.HTTP_400_BAD_REQUEST)

        # 地址模型 得到具体的地址信息
        # 省  市  区  详情   收件人  手机号
        address_res= f"""{address.province.name}
        {address.city.name}
        {address.district.name}
        【{address.mobile}】
        {address.place}"""

        # 生成订单号   20250702211113
        #                                 "20250702211113"   "000005" "000100"
        order_id = datetime.now().strftime("%Y%m%d%H%M%S")+  "%6d%2d" %  (request.user.id , random.randint(0,99))

        # 类似于  机器扫码  之后的 小票
        # 生成一个空白的订单记录信息  小票
        #   开启事务
        with transaction.atomic():
            # 初始点
            save_point = transaction.savepoint()
            try:
                order = Order.objects.create(
                    order_id = order_id,
                    pay_method = pay_method,
                    address = address_res,
                    status =  1  if pay_method == "1" else 2, #  待支付 1    else  待发货
                    total_count = 0,  # 总数
                    total_amount = decimal.Decimal("0"),  # 总价格
                    user = user
                )


                # 循环购物车  进行核算
                for cart_id in carts: # ["1","2"]  # 12 购物车列表id
                    while True:
                        # 通过购物车的id   正向查询 得到商品数据
                        try:
                            # cart 得到是 购物车模型
                            cart = ShoppingCart.objects.get(id = cart_id)
                        except ShoppingCart.DoesNotExist:
                            raise  ValidationError("购物的商品信息不存在")


                        # 正向查询 得到商品模型
                        commodity  = cart.commodity

                        # 根据商品模型 查询 库存 和销量
                        old_stock = commodity.stock
                        old_sales = commodity.sales

                        # 应该检查一下商品的库存
                        if cart.number > old_stock:
                            raise ValidationError("库存不足")
                            # return Response(status=status.HTTP_404_NOT_FOUND)

                        # 购买了商品后 库存减少  销量增加
                        new_stock = old_stock - cart.number # 新库存  = 原来的库存 - 购买的数量
                        new_sales = old_sales + cart.number # 新销量  = 原来的销量 + 购买的数量

                        # 商品表数据更新
                        # commodity.stock = new_stock
                        # commodity.sales = new_sales
                        # commodity.save()
                        #判断数据是否发送变化
                        #如果数据发生变化  那么久重新获取库存
                        # 乐观锁是逻辑
                        # update 更新成功  返回 1  如果更新失败 返回 0
                        # 如果查询的时候 stock = old_stock 不对了            old_stock =  100    实际只有50
                        res = Commodity.objects.filter(id = commodity.id,stock = old_stock).update(stock=new_stock, sales=new_sales)
                        # res = 0 库存发生了变化
                        # 进行重新获取库存
                        if not res:  # not False
                            continue


                        # 订单模型 也要进行更新
                        # 7                       0                 5
                        # 4                       5                 8
                        order.total_count =   order.total_count + cart.number
                        # 7                       0                 60 * 5
                        # 4                      300                30  *  8
                        order.total_amount  = order.total_amount + (commodity.price * cart.number)

                        # 关联的订单商品的记录  ==》订单详情
                        OrderGoods.objects.create(
                            order = order,
                            number = cart.number,
                            price = commodity.price,
                            commodity = commodity,
                        )
                        break

                # 订单表进行存储
                order.save() #01   bd1   13   540   xxxxxx    xxx  xxxx


            except  Exception as e:
                # 事务回滚
                transaction.savepoint_rollback(save_point)
                return  Response({"error":str(e)},status=status.HTTP_400_BAD_REQUEST)
            else:
                # 事务提交
                transaction.savepoint_commit(save_point)
        # 购物车清空                           [1,2]
        ShoppingCart.objects.filter(id__in =carts).delete()
        # 序列化返回
        serializer = self.get_serializer(order)
        return Response(serializer.data,status=status.HTTP_201_CREATED)


    # 修改订单状态
    @action(detail=False, methods=["put"])
    def status(self, request):
        """
                http://127.0.0.1:8080/order/success?
                charset=utf-8&out_trade_no=20250702222703+++++575&
                method=alipay.trade.page.pay.return&
                total_amount=111.00&sign=b9nD2RK%2B8TMD6HGYX99nFAGExyDxZq3z8UGEpapdZciqYQNXZQjyf62XP%2FnXB3w0kL4HtoxkEzJazt7USlRTELqNYiNhAkh9Lmfg%2F02BNNI2RMO6bBDo2Ru05O3zDh8e8RUf%2Fk54eaG%2BiMXrWMsImfSWZQW28qs4SRkxNlyHl1enqNEzBFrHNl8l%2FnNP5261K%2BRqQ9gYjncvXCSM07Sdts6PgsENbGRFewVCO516t%2FMQV90pS5lEq3NBDrPgOvgcRKggzR95SaD4lj4pH2VM6VXtLRfDN2G27h98SpkHB5e2pyz82POY3AvyVZ%2FQVCTDaIlLN3P9Gr7RjLbIUajSMQ%3D%3D&
                trade_no=2025070422001473120505918951&auth_app_id=9021000144615477&version=1.0&
                app_id=9021000144615477&sign_type=RSA2&seller_id=2088721058250983&
                timestamp=2025-07-04+20%3A39%3A17
        """
        data = request.query_params.dict()

        # 订单号
        out_trade_no =  data.get("out_trade_no")
        # 交易号
        trade_id = data.get("trade_no")
        with transaction.atomic():
            sava_point = transaction.savepoint()
            try:
                Payment.objects.create(trade_id = trade_id, order_id = out_trade_no)
                # 修改订单状态
                self.get_queryset().filter(order_id = out_trade_no,status=1).update(status=2)
            except Exception as e :
                transaction.savepoint_rollback(sava_point)
                raise  serializers.ValidationError(e)
            else:
                transaction.savepoint_commit(sava_point)
                # 交易完成delay() 异步方法
                # email  html_message  谁买了商品 就给谁发送邮箱的
                # 获取 ordergoods_set 订单详情表的数据
                # order (班级表)   ordergoods_set（学生表）
                ordergoods_res = self.get_queryset().get(order_id = out_trade_no).ordergoods_set.all()
                ordergood_li = []
                # for ordergood in ordergoods_res:
                #     send_mail_task.delay(ordergood.order.user.email,f"""
                #     <h1>恭喜您下单成功</h1>
                #     <h3>您购买了{ordergood.commodity.name} , {ordergood.number},价格是{ordergood.price}</h3>
                #     """)
                #
                for ordergood in ordergoods_res:
                    ordergood_li.append(f"<h3>您购买了{ordergood.commodity.name} , {ordergood.number},价格是{ordergood.price}</h3>")
                send_mail_task.delay(ordergood.order.user.email, f"""
                                     <h1>恭喜您下单成功</h1>
                                     <h3>f{ordergood_li}</h3>
                                     """)
        return Response({"order_id":out_trade_no,"trade_id":trade_id},status=status.HTTP_201_CREATED)





class PaymentViewSet(ReadOnlyModelViewSet):
    queryset = Payment.objects.all()
    serializer_class = PaymentSerializer
    permission_classes = [IsAuthenticated]


    # http://127.0.0.1:8000/shopping/payments/20250702222703%20%20%20%20%20575/pay/
    @action(detail=True, methods=["GET"])
    def pay(self,request, pk):
        # pk  = 20250702222703%20%20%20%20%20575
        try:
            # 获取订单信息 必须是未支付的 并且是当前用户的
            order = Order.objects.get(order_id=pk,user = request.user,status = 1)
        except Order.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)

        # 配置参数
        order_res = alipy.api_alipay_trade_page_pay(
            subject = f"jutong系统",  # 标题
            out_trade_no = str(order.order_id),# 订单号
            total_amount = str(order.total_amount), # 总金额
            return_url = "http:127.0.0.1:8080/order/success" # 支付成功的调整页面
        )

        # 订单  金额  掉用那个接口来支付呢
        pay_url = 'https://openapi-sandbox.dl.alipaydev.com/gateway.do?'+order_res

        # 返回支付地址
        return Response({"pay_url":pay_url})














